#ifndef __COMMON_DEFS_H__
#define __COMMON_DEFS_H__

#include <cstring>
#include <stdlib.h>
#include <stdio.h>

#define _NElem(array) (sizeof(array)/sizeof((array)[0]))

#define _ZeroStruct(p) memset((p), 0, sizeof(*(p)))

#define ALIGNED_FOR_DMA __attribute__((aligned(128)))

#define TAG_MASK(tag) ((uint32_t)(1 << (tag)))

// static assert support
template<bool condition> class _StaticAssertion;
template<> class _StaticAssertion<true> {};
template<int size> class _StaticAssertionTest {};

#define _DO_JOIN_TOKENS(a, b) a##b
#define _JOIN_TOKENS(a, b) _DO_JOIN_TOKENS(a, b)

#define STATIC_ASSERT(condition) typedef _StaticAssertionTest< sizeof(_StaticAssertion< (bool)(condition) >) > _JOIN_TOKENS(_StaticAssertion_, __LINE__)

static const unsigned int MAX_FORCE_INDEX = 10;
static const unsigned int MAX_PARTICLES = 254;

////////////////////////////////////////////////////////////////////////////////
// minimal possible configuration: 1 central volume and 6 adjacent, all adjacent interact
//      +------+------+------+
//      | z =-1| z = 0| z = 1|
//      +------+------+------+
//      |   x  |   x  |   x  |
//      |-1|0|1|-1|0|1|-1|0|1|
//+-----+--+-+-+--+-+-+--+-+-+
//|y =-1| . * .  . . .  . * .|
//|y = 0| . . .  . X *  . . *|
//|y = 1| . . .  . * .  * . .|
//+-----+--+-+-+--+-+-+--+-+-+
struct IntCoords {
    int i;
    int j;
    int k;
};
static const unsigned int SHIFTS_COUNT = 7;
static const IntCoords SHIFTS[SHIFTS_COUNT] = {
    {i: 0, j: 0, k: 0}, // central volume
    {i: 0, j:-1, k: 1},
    {i: 1, j: 0, k: 1},
    {i:-1, j: 1, k: 1},
    {i: 1, j: 0, k: 0},
    {i: 0, j: 1, k: 0},
    {i: 0, j:-1, k:-1},
};
inline bool shouldInteract(const int shift1, const int shift2) {
    return (shift1 != shift2 || (shift1 == 0 && shift2 == 0))
        && abs(SHIFTS[shift1].i - SHIFTS[shift2].i) <= 1
        && abs(SHIFTS[shift1].j - SHIFTS[shift2].j) <= 1
        && abs(SHIFTS[shift1].k - SHIFTS[shift2].k) <= 1;
}

template <class T>
inline T& SHIFT_IDX(T*** array, int k, int j, int i, int shift) {
    /*
    printf("    shift request: 0x%x[%d][%d][%d] ->", (int)(long long)array, k + SHIFTS[shift].k, j + SHIFTS[shift].j, i + SHIFTS[shift].i);
    fflush(stdout);
    T** array_k = array[k + SHIFTS[shift].k];
    printf(" 0x%x[%d][%d] ->", (int)(long long)array_k, j + SHIFTS[shift].j, i + SHIFTS[shift].i);
    fflush(stdout);
    T* array_k_j = array_k[j + SHIFTS[shift].j];
    printf(" 0x%x[%d] ->", (int)(long long)array_k_j, i + SHIFTS[shift].i);
    fflush(stdout);
    T& result = array_k_j[i + SHIFTS[shift].i];
    printf(" OK\n");
    fflush(stdout);
    return result;
    /*/
    return array[k + SHIFTS[shift].k][j + SHIFTS[shift].j][i + SHIFTS[shift].i];
}

#endif // __COMMON_DEFS_H__
